﻿using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Dynamic;
using System.Text;
using IntraVision.Web.Toolkit;

namespace IntraVision.Web.Filter
{
    public class DateFilterCondition<TEntity> : IFilterCondition<TEntity>
        where TEntity: class, new()
    {
        string _Column;
        string _Caption;
        bool _Nullable;
        DateTime _Date1 = DateTime.MinValue;
        DateTime _Date2 = DateTime.MinValue;
        int _Type = 0;

        public string Column
        {
            get { return _Column; }
            set { _Column = value; }
        }

        public bool Active
        {
            get { return _Type > 0 && (_Date1 != DateTime.MinValue || _Date2 != DateTime.MinValue); }
        }

        string[] _Types = { HTMLHelper.Resource("Filter", "Equal", "равно"), HTMLHelper.Resource("Filter", "BetweenInc", "между, включительно"), HTMLHelper.Resource("Filter", "BetweenExc", "между, исключительно"), HTMLHelper.Resource("Filter", "Defined", "задано"), HTMLHelper.Resource("Filter", "Undefined", "не задано") };

        public DateFilterCondition(string column, string caption, bool nullable)
        {
            _Column = column;
            _Caption = caption;
            _Nullable = nullable;
        }

        public DateFilterCondition(string column, string caption)
            : this(column, caption, false)
        {
        }

        #region IFilterCondition<TEntity> Members

        public IQueryable<TEntity> Filter(IQueryable<TEntity> list)
        {
            string nullable = _Nullable ? ".Value" : "";

            if (_Type == 4) return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} != null", _Column, nullable));
            if (_Type == 5) return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} == null", _Column, nullable));

            if (_Date1 == DateTime.MinValue && _Date2 == DateTime.MinValue) return list;
            bool d1t = (_Date1.Hour > 0 || _Date1.Minute > 0);
            bool d2t = (_Date2.Hour > 0 || _Date2.Minute > 0);

            switch (_Type)
            {
                case 1:
                    if (_Date1 == DateTime.MinValue) return list;
                    if (d1t)
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} == @0", _Column, nullable), _Date1);
                    else
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date == @0", _Column, nullable), _Date1);
                case 2:
                    if (_Date1 == _Date2)
                    {
                        if (_Date1.Hour > 0 || _Date1.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} == @0", _Column, nullable), _Date1);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date == @0", _Column, nullable), _Date1.Date);
                    }
                    if (_Date1 == DateTime.MinValue)
                    {
                        if (_Date2.Hour > 0 || _Date2.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} <= @0", _Column, nullable), _Date2);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date <= @0", _Column, nullable), _Date2.Date);
                    }
                    if (_Date2 == DateTime.MinValue)
                    {
                        if (_Date1.Hour > 0 || _Date1.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} >= @0", _Column, nullable), _Date1);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date >= @0", _Column, nullable), _Date1.Date);
                    }
                    if (_Date1.Hour > 0 || _Date1.Minute > 0 || _Date2.Hour > 0 || _Date2.Minute > 0)
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} >= @0 && {0}{1} <= @1", _Column, nullable), _Date1, _Date2);
                    else
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date >= @0 && {0}{1}.Date <= @1", _Column, nullable), _Date1.Date, _Date2.Date);
                case 3:
                    if (_Date1 == _Date2)
                    {
                        if (_Date1.Hour > 0 || _Date1.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} == @0", _Column, nullable), _Date1);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date == @0", _Column, nullable), _Date1.Date);
                    }
                    if (_Date1 == DateTime.MinValue)
                    {
                        if (_Date2.Hour > 0 || _Date2.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} < @0", _Column, nullable), _Date2);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date < @0", _Column, nullable), _Date2.Date);
                    }
                    if (_Date2 == DateTime.MinValue)
                    {
                        if (_Date1.Hour > 0 || _Date1.Minute > 0)
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} > @0", _Column, nullable), _Date1);
                        else
                            return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date > @0", _Column, nullable), _Date1.Date);
                    }
                    if (_Date1.Hour > 0 || _Date1.Minute > 0 || _Date2.Hour > 0 || _Date2.Minute > 0)
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1} > @0 && {0}{1} < @1", _Column, nullable), _Date1, _Date2);
                    else
                        return list.Where(string.Format(CultureInfo.InvariantCulture, "{0}{1}.Date > @0 && {0}{1}.Date < @1", _Column, nullable), _Date1.Date, _Date2.Date);
            }
            return list;
        }

        #endregion

        #region IFilterCondition Members

        public string Render()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format(CultureInfo.InvariantCulture, @"<div class=""filterfield""><table width=""100%""><tr><td class=""tdlabel""><label for=""flt1{0}"">{1}</label></td>", _Column, _Caption));
            sb.Append(string.Format(CultureInfo.InvariantCulture, @"<td class=""tdcondition""><select class=""flttype fttdate"" id=""ftt{0}"" name=""ftt{0}""><option value=""0"" />", _Column));
            for (int i = 0; i < _Types.Length; i++)
                sb.Append(string.Format(CultureInfo.InvariantCulture, @"<option value=""{0}"" {2}>{1}</option>", i + 1, _Types[i], ((_Type == (i + 1)) ? " selected" : "")));
            sb.Append("</select></td>");
            sb.Append(string.Format(CultureInfo.InvariantCulture, @"<td class=""tdvalue""><input class=""dateRU fltdate {4}"" type=""text"" id=""flt1{0}"" name=""flt1{0}"" value=""{2}"" /> <span class=""date2 {5}""> {6} <input class=""dateRU"" type=""text"" id=""flt2{0}"" name=""flt2{0}"" value=""{3}"" /></span></td></tr></table></div>"
                , _Column, _Caption, DateValue(_Date1), DateValue(_Date2), (_Type == 4 || _Type == 5) ? "hidden" : "", (_Type <= 1 || _Type == 4 || _Type == 5) ? "hidden" : "", HTMLHelper.Resource("Filter", "And", "и")));
            return sb.ToString();
        }

        private static string DateValue(DateTime date)
        {
            if (date == DateTime.MinValue) return "";
            if (date.Hour > 0 || date.Minute > 0 || date.Second > 0)
                return date.ToString("dd.MM.yyyy HH:mm", CultureInfo.InvariantCulture);
            else
                return date.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture);
        }

        public void Init(NameValueCollection req)
        {
            var culture = new CultureInfo("ru-RU");
            //Парсим даты по правилам русской культуры
            if (!string.IsNullOrEmpty(req["flt1" + _Column]))
                DateTime.TryParse(req["flt1" + _Column], culture.DateTimeFormat, DateTimeStyles.None, out _Date1);
            if (!string.IsNullOrEmpty(req["flt2" + _Column]))
                DateTime.TryParse(req["flt2" + _Column], culture.DateTimeFormat, DateTimeStyles.None, out _Date2);
            if (!string.IsNullOrEmpty(req["ftt" + _Column]))
                Int32.TryParse(req["ftt" + _Column], out _Type);
        }

        #endregion

        public override string ToString()
        {
            if (_Type <= 0) return string.Empty;
            return string.Format("ftt{0}={1}&flt1{0}={2}&flt2{0}={3}", _Column, _Type, _Date1.ToDateString(), _Date2.ToDateString());
        }
    }
}
